package org.particlethink.singleflight;

import org.particlethink.job.Result;
import org.particlethink.job.Runnable;

import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;

public class SingleFlight {
    private final ConcurrentHashMap<String, SingleResult<Object>> results = new ConcurrentHashMap<>();

    public Result<Object> Do(String name, Runnable<Object> task) {
        SingleResult<Object> result = new SingleResult<>(new Date());
        SingleResult<Object> oldResult = results.putIfAbsent(name, result);
        if (oldResult == null) {
            Result<Object> lastResult = null;
            try {
                lastResult = task.run();
            } catch (InterruptedException e) {
                lastResult = new SingleResult<>(null, new Date(), true, e);
            }
            synchronized (result) {
                result.copy(lastResult);
                result.notifyAll();
            }
            return result;
        }
        synchronized (oldResult) {
            while (!oldResult.isDone()) {
                try {
                    oldResult.wait();
                } catch (InterruptedException e) {
                    oldResult.setException(e);
                    oldResult.done();
                    return oldResult;
                }
            }
        }
        return oldResult;
    }
}
